{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ace56453",
   "metadata": {},
   "source": [
    "![MuJoCo banner](https://raw.githubusercontent.com/google-deepmind/mujoco/main/banner.png)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Copyright notice\n",
    "\n",
    "> <p><small><small>Copyright 2025 DeepMind Technologies Limited.</small></p>\n",
    "> <p><small><small>Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</a>.</small></small></p>\n",
    "> <p><small><small>Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.</small></small></p>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25844711",
   "metadata": {},
   "source": [
    "# Tutorial\n",
    "\n",
    "This notebook is the first of two that demonstrate pixels-to-actions training using the experimental Madrona rendering backend. \n",
    "\n",
    "### Usage\n",
    "\n",
    "Please note that this Colab **does not support a hosted runtime**. To use it, please install [Madrona-MJX](https://github.com/shacklettbp/madrona_mjx/tree/main) and Playground on your local device and select `Connect to a local runtime`, or download the notebook to run locally! We recommend a device with at least 24 GB VRAM, such as the RTX4090."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "92bcc22b",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [],
   "source": [
    "# @title Import MuJoCo, MJX, and Brax\n",
    "from datetime import datetime\n",
    "import functools\n",
    "import os\n",
    "import time\n",
    "\n",
    "from brax.training.agents.ppo import networks_vision as ppo_networks_vision\n",
    "from brax.training.agents.ppo import train as ppo\n",
    "from IPython.display import clear_output\n",
    "import jax\n",
    "from jax import numpy as jp\n",
    "from matplotlib import pyplot as plt\n",
    "import mediapy as media\n",
    "import numpy as np\n",
    "\n",
    "from mujoco_playground import wrapper\n",
    "\n",
    "np.set_printoptions(precision=3, suppress=True, linewidth=100)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d7b9ef23",
   "metadata": {},
   "outputs": [],
   "source": [
    "# On your second reading, load the compiled rendering backend to save time!\n",
    "# os.environ[\"MADRONA_MWGPU_KERNEL_CACHE\"] = \"<YOUR_PATH>/madrona_mjx/build/cache\"\n",
    "\n",
    "# Coordinate between Jax and the Madrona rendering backend\n",
    "def limit_jax_mem(limit):\n",
    "  os.environ[\"XLA_PYTHON_CLIENT_MEM_FRACTION\"] = f\"{limit:.2f}\"\n",
    "\n",
    "\n",
    "limit_jax_mem(0.6)\n",
    "# Reduce madrona memory allocation to 1GB as cartpole doesn't need much\n",
    "os.environ[\"MADRONA_MWGPU_DEVICE_HEAP_SIZE\"] = \"1073741824\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4cda76c2",
   "metadata": {},
   "source": [
    "## Introducing Madrona MJX\n",
    "\n",
    "[Madrona MJX](https://github.com/shacklettbp/madrona_mjx/tree/main) is Mujoco's experimental on-device rendering backend, developed in collaboration with [Madrona](https://github.com/shacklettbp/madrona). It implements a JAX-compatible batched renderer for rolling out multiple training environments in parallel.\n",
    "\n",
    "*The Rendering Bottleneck*\n",
    "\n",
    "In Reinforcement Learning, an agent uses a policy to produce an action $a_t$ in response to an observation $o_t$ of the simulation state. The environment evaluates the interaction via a reward signal $r_t$, then transitions to the next state rendered as $o_{t+1}$. Together, this forms the [transition](https://github.com/google/brax/blob/69637a359463738140c1b850f61ad0088a23538b/brax/training/types.py#L43) $(o_t, a_t, r_t, o_{t+1})$, the basic data unit of a RL training pipeline. Due to poor sample efficiency, the speed of collecting transitions is the often the bottle-neck in on-policy RL methods such as PPO. In addition to full-body physics simulation - for example `mujoco.mjx.step` - pixels-based training requires an expensive call to a renderer on every transition. Along with the cost of expensive CNN architectures, rendering speed becomes a significant performance consideration.\n",
    "\n",
    "*Coming Up*\n",
    "\n",
    "In this tutorial, we'll use a high-performance ray-tracing backend to render images in parallel across a batch of environments. Before we get to sub-minute pixel-based training, let's see how much faster Madrona's batched rendering lets us collect raw transitions. For a baseline, let's load the Cartpole Task from dm_control, a popular reference library built on Mujoco:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7f95626b",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [],
   "source": [
    "from dm_control import suite\n",
    "\n",
    "env = suite.load(\"cartpole\", \"balance\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "2f1e5136",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dm_control: 836 transitions per second\n"
     ]
    }
   ],
   "source": [
    "N = 1000\n",
    "img_shape = (64, 64)\n",
    "env.reset()\n",
    "t0 = time.time()\n",
    "for i in range(N):\n",
    "  act = np.random.uniform(low=-1.0, high=1.0)\n",
    "  env.step(act)\n",
    "  _pixels = env.physics.render(\n",
    "      camera_id=0, height=img_shape[0], width=img_shape[1]\n",
    "  )\n",
    "dt = time.time() - t0\n",
    "\n",
    "print(\"dm_control: {:d} transitions per second\".format(int(N / dt)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0902bd0d",
   "metadata": {},
   "source": [
    "Now, let's load Mujoco Playground's JAX Cartpole re-implementation. While we're at it, we'll configure it for the upcoming training."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "743928b0",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [],
   "source": [
    "from mujoco_playground import dm_control_suite\n",
    "\n",
    "\n",
    "num_envs = 1024\n",
    "ctrl_dt = 0.04\n",
    "episode_length = int(3 / ctrl_dt)\n",
    "\n",
    "config_overrides = {\n",
    "    \"vision\": True,\n",
    "    \"vision_config.render_batch_size\": num_envs,\n",
    "    \"action_repeat\": 1,\n",
    "    \"ctrl_dt\": ctrl_dt,\n",
    "    \"episode_length\": episode_length,\n",
    "}\n",
    "\n",
    "env_name = \"CartpoleBalance\"\n",
    "env = dm_control_suite.load(\n",
    "    env_name, config_overrides=config_overrides\n",
    ")\n",
    "\n",
    "env = wrapper.wrap_for_brax_training(\n",
    "    env,\n",
    "    vision=True,\n",
    "    num_vision_envs=num_envs,\n",
    "    action_repeat=1,\n",
    "    episode_length=episode_length,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c4d70a08",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [],
   "source": [
    "jit_reset = jax.jit(env.reset)\n",
    "jit_step = jax.jit(env.step)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "1d16dd6c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Madrona MJX: 290656 transitions per second\n"
     ]
    }
   ],
   "source": [
    "key_reset, key_act = jax.random.split(jax.random.PRNGKey(0))\n",
    "state = jit_reset(jax.random.split(key_reset, num_envs))\n",
    "\n",
    "# Pre-compile\n",
    "jit_step = jit_step.lower(\n",
    "    state, jp.zeros((num_envs, env.action_size))\n",
    ").compile()\n",
    "\n",
    "t0 = time.time()\n",
    "for i in range(N):\n",
    "  act = jax.random.uniform(\n",
    "      key_act, (num_envs, env.action_size), minval=-1.0, maxval=1.0\n",
    "  )\n",
    "  state = jit_step(state, act)\n",
    "\n",
    "jax.tree_util.tree_map(\n",
    "    lambda x: x.block_until_ready(), state\n",
    ")  # Await device completion\n",
    "dt = time.time() - t0\n",
    "\n",
    "print(\"Madrona MJX: {:d} transitions per second\".format(int(N * num_envs / dt)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ab3a297",
   "metadata": {},
   "source": [
    "## Balancing a Cartpole\n",
    "\n",
    "Now, let's train a pixels-to-torque policy to balance a cartpole. In [our implementation]((https://github.com/kevinzakka/mujoco_playground/blob/main/mujoco_playground/_src/dm_control_suite/cartpole.py)), we control the observation dimensionality while encouraging the agent to understand dynamics by setting the observations as grayscale images stacked across sequential timesteps."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59f3b3ac",
   "metadata": {},
   "source": [
    "#### Visualize the environment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b1286e8",
   "metadata": {},
   "outputs": [],
   "source": [
    "def unvmap(x):\n",
    "  return jax.tree.map(lambda y: y[0], x)\n",
    "\n",
    "\n",
    "state = jit_reset(jax.random.split(jax.random.PRNGKey(0), num_envs))\n",
    "rollout = [unvmap(state)]\n",
    "\n",
    "f = 0.2\n",
    "for i in range(episode_length):\n",
    "  action = []\n",
    "  for j in range(env.action_size):\n",
    "    action.append(\n",
    "        jp.sin(\n",
    "            unvmap(state).data.time * 2 * jp.pi * f\n",
    "            + j * 2 * jp.pi / env.action_size\n",
    "        )\n",
    "    )\n",
    "  action = jp.tile(jp.array(action), (num_envs, 1))\n",
    "  state = jit_step(state, action)\n",
    "  rollout.append(unvmap(state))\n",
    "\n",
    "frames = env.render(rollout, camera=\"fixed\", width=256, height=256)\n",
    "k = next(iter(rollout[0].obs.items()), None)[0]  # ex: pixels/view_0\n",
    "obs = [r.obs[k][..., 0] for r in rollout]  # visualise first channel\n",
    "\n",
    "media.show_videos([frames, obs], fps=1.0 / env.dt, height=256)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "686f6663",
   "metadata": {},
   "source": [
    "#### Train\n",
    "Training the policy takes 57s on a RTX4090 GPU."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "06333cd4",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [],
   "source": [
    "from mujoco_playground.config import dm_control_suite_params\n",
    "\n",
    "# Load vision-specific PPO configuration tuned for CartpoleBalance\n",
    "ppo_params = dm_control_suite_params.brax_vision_ppo_config(env_name)\n",
    "ppo_params.episode_length = episode_length\n",
    "ppo_params.network_factory = ppo_networks_vision.make_ppo_networks_vision"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2f419702",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [],
   "source": [
    "x_data, y_data, y_dataerr = [], [], []\n",
    "times = [datetime.now()]\n",
    "\n",
    "\n",
    "def progress(num_steps, metrics):\n",
    "  clear_output(wait=True)\n",
    "\n",
    "  times.append(datetime.now())\n",
    "  x_data.append(num_steps)\n",
    "  y_data.append(metrics[\"eval/episode_reward\"])\n",
    "  y_dataerr.append(metrics[\"eval/episode_reward_std\"])\n",
    "\n",
    "  plt.xlim([0, ppo_params[\"num_timesteps\"] * 1.25])\n",
    "  plt.ylim([0, 100])\n",
    "  plt.xlabel(\"# environment steps\")\n",
    "  plt.ylabel(\"reward per episode\")\n",
    "  plt.title(f\"y={y_data[-1]:.3f}\")\n",
    "  plt.errorbar(x_data, y_data, yerr=y_dataerr, color=\"blue\")\n",
    "\n",
    "  display(plt.gcf())\n",
    "\n",
    "\n",
    "train_fn = functools.partial(\n",
    "    ppo.train, **dict(ppo_params), progress_fn=progress\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3fb88915",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAS8tJREFUeJzt3Xd8VFXex/HvpEMgoadQI4L03gLSJAjCYgEWcUNREfaRsihNkAXEhrKorBWl6kpZEbAgAhqlGimhCYaONElAMQkJJKTc54/ZTDImQAYmmcnl83695vVkzpy588t9sszXc889x2IYhiEAAACT8nB1AQAAAIWJsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAPArdWoUUMWiyXfR61atWz9Tp8+renTp6tVq1YqW7asKlSooE6dOunbb78t8GedO3dOw4YNU1hYmEqUKKGaNWtqzJgx+v333/P0ffvtt1W3bl35+vqqcuXKGjNmjFJSUuz6HDx4UBMmTFCTJk1UunRphYSEqGfPntq5c+fNnxAADrOwNxYAd/bZZ58pOTnZru3kyZP65z//qeHDh+udd96RZA0fEyZM0IMPPqh27dopIyNDH330kXbt2qUFCxboscceu+7nJCcnq0GDBkpJSdHw4cNVtWpV7d27V++//77q16+vmJgYeXhY//vwmWee0cyZM9W3b1916dJFP//8s9577z3dc889Wrdune2Y48aN0/z589WnTx+1atVKiYmJev/99/XLL79o7dq1ioiIcPLZApAvAwCKmRdeeMGQZGzdutXWtn//fuPChQt2/VJTU406deoYVapUueExFy9ebEgyVq9ebdc+depUQ5Kxa9cuwzAM49dffzW8vLyMgQMH2vV76623DEnGF198YWvbuXOncenSJbt+v/32m1GxYkWjXbt2BftlAdwyLmMBuCXff/+9LBaLVq1alee1JUuWyGKxKDo62qmfuWTJEoWFhalt27a2tvr166tChQp2/Xx9fdWjRw+dOXNGly5duu4xk5KSJElBQUF27SEhIZKkEiVKSJKio6OVkZGh/v372/XLfr5s2TJbW/PmzVWqVCm7fuXLl1f79u0VGxt7w98TgHN4uboAAMVbp06dVLVqVS1evFgPPfSQ3WuLFy9WzZo1FR4errS0tBsGjmx/Di257d69W7GxsZo8eXKBjhUXF6eSJUuqZMmS1+3XoUMHeXh4aPTo0XrttddUpUoV7du3Ty+99JIefPBB1alTR5KUlpYmKSf8ZMs+fkxMTIFqut7vCMC5GNkBcEssFosGDBig1atXKzEx0dZ+4cIFrV+/XgMGDJAkLV26VBUrVizQ43oWL14sSYqMjLxhbUePHtXKlSvVp08feXp6XrdvvXr19MEHH+jnn39WeHi4qlatqp49e6pLly5avny5rd9dd90lSdq6davd+zdv3ixJOnv27HU/Z/PmzYqOjtbDDz98w/oBOAcTlAHcsoMHD6pu3bqaN2+ehgwZIsk6YXjUqFE6cuSI7rzzTp07d04HDhwo0PGuNXE3KytL1apVU6VKlbRr167rHuPy5ctq166dTp48qf379ys0NPSGn7t27Vq98cYb6tGjh6pXr67NmzfrzTff1OjRozVr1ixbvzZt2ujAgQN688031blzZ8XGxurJJ5/Ur7/+qqysLGVkZOR7/PPnz6t58+by8fHR3r1781ziAlBIXD1pCIA5tGzZ0ujcubPteZs2bYw2bdo49TO+++47Q5Ixa9as6/bLyMgwevXqZfj4+BhRUVEFOvaWLVsMT09PY8eOHXbtzz33nGGxWIwDBw7Y2s6cOWO0a9fOkGRIMjw9PY3x48cbrVq1MgIDA/M9fnJystGyZUsjMDDQ+OmnnwpUEwDnYM4OAKcYNGiQRo8erTNnzigtLU0//vij3n77bdvrV65csbvMdT3BwcH5ti9evFgeHh565JFHrvv+oUOHavXq1Vq8eLHuueeeAn3m+++/r6CgILVo0cKu/f7779dzzz2nH374QfXq1ZMkVa5cWVu2bNGRI0cUFxenWrVqKTg4WKGhoapdu3aeY1+9elW9e/fWvn37tG7dOjVo0KBANQFwDsIOAKfo37+/xowZo6VLl+rKlSvy9va2m5fy3//+94Zr3WQz8rm6npaWphUrVqhTp07XvSQ1fvx4LVy4ULNnz75hKMotPj5emZmZedrT09MlKd9LU7Vq1bItbPjzzz/r3LlzevTRR+36ZGVladCgQYqKitInn3yijh07FrgmAM5B2AHgFBUqVNB9992njz/+WKmpqerevbvdHUfdunXTN998c9PHX7NmjRISEq47Mflf//qXZs2apWeffVajR4++Zr/ExESdO3dOISEhCgwMlCTVrl1b69ev14YNG9SpUydb36VLl0qSmjZtes3jZWVlacKECSpZsqT+7//+z+61UaNG6b///a/ef/999e7duyC/KgAnY4IyAKdZsWKF+vbtK8k6ktOvXz+nHbtv375avXq14uPjbQElt1WrVql3796qVauWpk6dmuf1rl272tbQWbRokR577DEtXLjQNhJz6NAhNW/eXBaLRaNGjVL16tW1ceNGLV26VF27dtX69ettxxo9erRSU1PVpEkTpaena8mSJdq+fbs+/PBDDRw40NZv9uzZevrppxUeHq7hw4fnqemhhx6Sv7//rZ4aADfAyA4Ap+nVq5fKli2rrKws3X///U47blJSkr766iv17Nkz36AjSXv37pUkHTlyxC5wZPv+++/zLBiY21133aWYmBj985//1Mcff6y4uDiFhoZq3Lhxmj59ul3fpk2bavbs2bY5RK1atVJUVJQ6d+5s12/Pnj2SrAsR5rew4okTJwg7QBFgZAeA02RkZCg0NFS9evXS/PnzXV0OAEhiUUEATvTZZ5/pwoULGjRokKtLAQAbRnYA3LJt27Zp3759euGFF1ShQoUbLvgHAEWJkR0At+y9997Tk08+qUqVKumjjz5ydTkAYMelYWfTpk3q1auXQkNDZbFY9Nlnn9m9bhiGpk6dqpCQEJUoUUIRERE6cuSIXZ+LFy8qMjJSAQEBKlOmjIYMGaLk5OQi/C0ALFq0SBkZGdq5cycL5gFwOy4NOykpKWrcuLHeeeedfF+fOXOm3nzzTc2ZM0fbtm2Tv7+/unXrptTUVFufyMhIHThwQN98841Wr16tTZs2adiwYUX1KwAAADfnNnN2LBaLVq1apQcffFCSdVQnNDRUY8eO1bhx4yRZFwILCgrSokWL1L9/f8XGxqpevXrasWOHbYn3tWvXqkePHjpz5kyBNv4DAADm5rbr7Jw4cUJxcXF2ux8HBgaqdevWio6OVv/+/RUdHa0yZcrY7WUTEREhDw8Pbdu2TQ899FC+x05LS1NaWprteVZWli5evKjy5cvLYrEU3i8FAACcxjAMXbp0SaGhofLwuPbFKrcNO3FxcZKUZxGwoKAg22txcXGqVKmS3eteXl4qV66crU9+ZsyYkWeRMAAAUDydPn1aVapUuebrbht2CtOkSZM0ZswY2/PExERVq1ZNp0+fVkBAgAsrAwAABZWUlKSqVauqdOnS1+3ntmEnODhYknUn4pCQEFt7fHy8mjRpYutz/vx5u/dlZGTo4sWLtvfnx9fXV76+vnnaAwICCDsAABQzN5qC4rbr7ISFhSk4OFhRUVG2tqSkJG3btk3h4eGSpPDwcCUkJCgmJsbW57vvvlNWVpZat25d5DUDAAD349KRneTkZB09etT2/MSJE9qzZ4/KlSunatWq6amnntKLL76oWrVqKSwsTFOmTFFoaKjtjq26deuqe/fuGjp0qObMmaP09HSNHDlS/fv3504sAAAgycVhZ+fOnXa7BGfPoxk8eLAWLVqkCRMmKCUlRcOGDVNCQoLuvvturV27Vn5+frb3LF68WCNHjlSXLl3k4eGhPn366M033yzy3wUAALgnt1lnx5WSkpIUGBioxMRE5uwAAFBMFPT7223n7AAAADgDYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJiaW4edzMxMTZkyRWFhYSpRooRq1qypF154QYZh2PoYhqGpU6cqJCREJUqUUEREhI4cOeLCqgEAgDtx67Dz6quv6r333tPbb7+t2NhYvfrqq5o5c6beeustW5+ZM2fqzTff1Jw5c7Rt2zb5+/urW7duSk1NdWHlAADAXViM3MMkbuYvf/mLgoKCNH/+fFtbnz59VKJECX388ccyDEOhoaEaO3asxo0bJ0lKTExUUFCQFi1apP79+xfoc5KSkhQYGKjExEQFBAQUyu8CAACcq6Df3249stO2bVtFRUXp8OHDkqS9e/dqy5Ytuu+++yRJJ06cUFxcnCIiImzvCQwMVOvWrRUdHX3N46alpSkpKcnuAQAAzMnL1QVcz8SJE5WUlKQ6derI09NTmZmZeumllxQZGSlJiouLkyQFBQXZvS8oKMj2Wn5mzJih6dOnF17hAADAbbj1yM4nn3yixYsXa8mSJdq1a5c+/PBDzZo1Sx9++OEtHXfSpElKTEy0PU6fPu2kigEAgLtx65Gd8ePHa+LEiba5Nw0bNtTJkyc1Y8YMDR48WMHBwZKk+Ph4hYSE2N4XHx+vJk2aXPO4vr6+8vX1LdTaAQCAe3DrkZ3Lly/Lw8O+RE9PT2VlZUmSwsLCFBwcrKioKNvrSUlJ2rZtm8LDw4u0VgAA4J7cemSnV69eeumll1StWjXVr19fu3fv1uuvv67HH39ckmSxWPTUU0/pxRdfVK1atRQWFqYpU6YoNDRUDz74oGuLBwAAbsGtw85bb72lKVOmaPjw4Tp//rxCQ0P197//XVOnTrX1mTBhglJSUjRs2DAlJCTo7rvv1tq1a+Xn5+fCygEAgLtw63V2igrr7AAAUPyYYp0dAACAW0XYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQAApkbYAQDAjaSkSBaL9ZGS4upqzIGwAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwAATI2wAwCAG8jIkPbulRYtymk7dcpl5ZiKl6sLAADgdmMY0vHj0o4d0vbt1v8bEyNduWLfb+dOqW5d19RoJoQdAE5x4oR0xx3Wn48fl8LCXFsP8nf+vBQUZP05Pl6qVMm19dwu4uPtg8327dLFi3n7lS4tNWsmbdxofd6hQ9HWaVaEHQAAnCgpyTpKkzvc5Hc5ysdHatJEatVKatnS+n9r17aO7pQqZe1ToUKRlm5ahB0AAG5SWpq0b599sImNtV6mys1isV6Oyh1sGjaUfH1dU/fthrADAEABZGVJhw7ZB5s9e6SrV/P2rVbNPtg0ayYFBBR5yfgfwg4AAH9iGNKZM/ZzbGJirJeo/qxcOWugyQ43LVvmzIuCeyDsAABuexcvWkNN7lGbuLi8/UqWtI7S5B61CQuzXqaC+yLsAABuK5cvS7t32webo0fz9vP0tM6ryR1s6tWTvAr5m9PfP++cH9wawg4AwLQyMqQDB+wvR+3fL2Vm5u175532l6OaNLGO5KD4I+wAAEwhe6G+3MFm1668C/VJUnCwfbBp0cI69wbmRNgBABRLcXF559nkt1BfQIA1zOS+HFW5MvNsbieEHQCA28teqC/3qM3p03n75V6oLzvc1K4tebAT5G2NsAMAcCvZC/XlDjYHD+a/UF+9ejmjNS1bSo0aWQMPkBthBwDgMtkL9eUONnv35r9QX/Xq9sGmeXPrXlLAjRB2AABFIvdCfdnhZudO6dKlvH3Ll88JNtnhhk1LcbMIOwCAQpG9UF/uUZv4+Lz9Spa0jtLkHrVhoT44E2EHAHDLshfqyx1sjh3L28/T0zqvJnewKYqF+nB7488LAOCQ3Av1ZYebay3UV6uW/eWoJk2kEiWKvGTc5gg7AIBrMgzrCE3uy1HXW6ivdeuccNOihVS2bNHXDPzZTYWdzZs36/3339exY8f06aefqnLlyvrPf/6jsLAw3X333c6uEQBQRLIX6ssONtdbqC97h+/sy1Es1Ad35XDYWbFihQYOHKjIyEjt3r1baWlpkqTExES9/PLLWrNmjdOLBAA436VLeS9HXWuhvqZN7S9H1arFQn0oPhwOOy+++KLmzJmjQYMGadmyZbb2du3a6cUXX3RqcQCAgsnKkhISrLd2nz1rHaGJj5cuXJB+/1364w/r67lHaWrVuvZCfbm3VmjYkIX6ULw5HHYOHTqkDh065GkPDAxUQkKCM2oCgNtKVpY1hJw5I/36q3TunHT+fE5QuXhRSky0bpmQnGy98+nKFetKw+np1onBfw4tBWEY1oX6cgebZs1YqA/m43DYCQ4O1tGjR1WjRg279i1btuiOO+5wVl0AUCxkZVlDSXZQiYuzDyrZIyqXLuUEldTUWw8qN+LpKXl7W0dk/Pysd0CVKmX9OSbG2mf/fql+fed/NuBuHA47Q4cO1ejRo7VgwQJZLBb9+uuvio6O1rhx4zRlypTCqBEACkVWljWcnD2bE1Ti46XffssJKomJ+QeVjIzCCSoWi3UuTO6gUrKkNaiULi0FBlrvcCpfXqpQwbqqcHCwFBpqnSAcHHz9NWvOn5eCgqw/V6zo3NoBd+Vw2Jk4caKysrLUpUsXXb58WR06dJCvr6/GjRunUaNGFUaNAJBHRkbeoHL+/I2DytWr1hGVrKzCCSqentaw4et746ASFJQ3qDDpF3A+h8OOxWLR5MmTNX78eB09elTJycmqV6+eSpUqVRj1ATChjAxrQMkOKvHxOZd+Ll7MG1SuXLEPKvktXnersoNK9ohKiRLWoOLvb73NOndQqVjRfkSlShXrc4IK4J5uelFBHx8f1atXz5m1ACjGcgeQ3r2twSQlxX5EJfvSj7PlDirZIyr+/jkjKmXKXHtEpUoVaxtBBTCvAoWd3r17F/iAK1euvOliABRPb78tPfVUzvM9ewr+XovFetknv6ASEGANKmXKWANJdlAJCckJKmXLElQAXF+Bwk5gYKDtZ8MwtGrVKgUGBqpFixaSpJiYGCUkJDgUigAUf8eOSe3bW2+Vzq1uXetlnewRlQoVrJd+skdUKle2BpUyZVxRNYDbTYHCzsKFC20/P/PMM+rXr5/mzJkjT09PSVJmZqaGDx+ugICAwqkSgFvJzJQefFBavTqnzcfHeqlKkr76SgoLc0lpAJCHw4O/CxYs0Lhx42xBR5I8PT01ZswYLViwwKnFAXA/8+ZZJ+/mDjoPPywdPOi6mgDgehwOOxkZGTqYz79qBw8eVFZWllOKAuB+Tp2SqlaVhg613hElSdWqWRfTy7VzDAC4HYfvxnrsscc0ZMgQHTt2TK1atZIkbdu2Ta+88ooee+wxpxcIwLUyM60jNytW5LR5e1tHeAYNcl1dAFBQDoedWbNmKTg4WK+99prO/W9WYkhIiMaPH6+xY8c6vUAArvPxx9KQITlzcSTrXJ1PP7Xe6g0AxYHDYcfDw0MTJkzQhAkTlJSUJElMTAZM5uxZqV076eTJnLbKlaXNm5l4DKD4uenVKS5cuKB9+/Zp3759+u2335xZEwAXioy03haeHXS8vKQPPrDOzSHoACiOHA47KSkpevzxxxUSEqIOHTqoQ4cOCgkJ0ZAhQ3T58uXCqBFAEVi+3Lqg35IlOW09elhXPx461HV1AcCtcjjsjBkzRhs3btSXX36phIQEJSQk6PPPP9fGjRuZswMUQxcuSHfeKfXrZ93NW7Iu/nfokHW9HObmACjuHA47K1as0Pz583XfffcpICBAAQEB6tGjh+bOnatPP/20MGoEUEgef9y60vGxY9bnnp7Sm29adxCvXdu1tQGAszg8Qfny5csKCgrK016pUiUuYwHFxOrV1pGcK1dy2rp0kdatYyQHgPk4PLITHh6uadOmKTU11dZ25coVTZ8+XeHh4U4tDoBzXbxo3beqV6+coFOhgvTTT9K33xJ0AJiTwyM7//73v9WtWzdVqVJFjRs3liTt3btXfn5+WrdundMLBOAcw4dL772X89zDQ5oxQ5owwXU1AUBRcDjsNGjQQEeOHNHixYtt20Y88sgjioyMVIkSJZxeIIBb88031oUAc19lbt/eOpLj4+OysgCgyDgcdiSpZMmSGlpE96KePXtWzzzzjL7++mtdvnxZd955pxYuXKgWLVpIkgzD0LRp0zR37lwlJCSoXbt2eu+991SrVq0iqQ9wV8nJUni4tH9/Tlu5clJUlNSkicvKgotVqiQZhqurAIqWw3N2PvzwQ3311Ve25xMmTFCZMmXUtm1bncy93KoT/PHHH2rXrp28vb319ddf6+eff9Zrr72msmXL2vrMnDlTb775pubMmaNt27bJ399f3bp1s5tTBNxuxoyRAgJygo6Hh/T889LvvxN0ANx+LIbhWMa/66679N577+mee+5RdHS0unTpotmzZ2v16tXy8vLSypUrnVbcxIkTtXXrVm3evDnf1w3DUGhoqMaOHatx48ZJkhITExUUFKRFixapf//+BfqcpKQkBQYGKjExka0vUKxt2GCdfJycnNPWpo20cWPhX7I6cUK64w7rz8ePs9oygMJX0O9vh0d2Tp8+rTvvvFOS9Nlnn6lv374aNmyYZsyYcc1QcrO++OILtWjRQn/9619VqVIlNW3aVHPnzrW9fuLECcXFxSkiIsLWFhgYqNatWys6Ovqax01LS1NSUpLdAyjOrlyRmjaVOnfOCTqBgdK2bVJ0NHNzANzeHA47pUqV0u+//y5JWr9+vbp27SpJ8vPz05Xci3Y4wfHjx23zb9atW6cnn3xS//jHP/Thhx9KkuLi4iQpz7o/QUFBttfyM2PGDAUGBtoeVatWdWrdQFGaNEny95f27LE+t1ikZ5+VEhKkVq1cWRkAuAeHJyh37dpVTzzxhJo2barDhw+rR48ekqQDBw6oRo0aTi0uKytLLVq00MsvvyxJatq0qfbv3685c+Zo8ODBN33cSZMmacyYMbbnSUlJBB4UOz/+KHXrJuUemGze3LozOTdGAkAOh0d23nnnHYWHh+vChQtasWKFypcvL0mKiYnRI4884tTiQkJCVK9ePbu2unXr6tSpU5Kk4OBgSVJ8fLxdn/j4eNtr+fH19bVtdZH9AIqLtDTriE14eE7QKV3aOi9n506CDgD8mcMjO2XKlNHbb7+dp3369OlOKSi3du3a6dChQ3Zthw8fVvXq1SVJYWFhCg4OVlRUlJr87xaTpKQkbdu2TU8++aTT6wFcbfp0611VWVnW5xaL9NRT0uuvu7QsAHBrBQo7+/btU4MGDeTh4aF9+/Zdt2+jRo2cUpgkPf3002rbtq1efvll9evXT9u3b9cHH3ygDz74QJJksVj01FNP6cUXX1StWrUUFhamKVOmKDQ0VA8++KDT6gBcLSZG6tpV+uOPnLaGDaUffpBKlXJdXQBQHBQo7DRp0kRxcXGqVKmSmjRpIovFotx3rGc/t1gsyszMdFpxLVu21KpVqzRp0iQ9//zzCgsL0+zZsxUZGWnrM2HCBKWkpGjYsGFKSEjQ3XffrbVr18rPz89pdQCucvWqdYPOLVty2vz9pVWrrOEHAHBjBVpn5+TJk6pWrZosFssNFw7MvsRUnLDODtzRq69a76rKfclq+HApn6vIboF1dgAUtYJ+fxdoZCd3gCmOYQYoTvbvlzp1sq52nK1OHevdV4GBLisLAIqtm9ob69ChQ3rrrbcUGxsryXqH1KhRo3TXXXc5tTjgdpKZab009f33OW0lSkiffCL95S+uq6ugwsLYcwmAe3L41vMVK1aoQYMGiomJUePGjdW4cWPt2rVLDRo00IoVKwqjRsD0Zs+WfH3tg84TT1h3Ki8OQQcA3JnDe2PVrFlTkZGRev755+3ap02bpo8//ljHjh1zaoFFgTk77u3AAalBA+vP+/dL9eu7th5nOnxYat9eOn8+p+3OO613WVWs6Lq6AKA4KLS9sc6dO6dBgwblaR8wYIDOnTvn6OGA21JmptS9u3TXXTlBx9dXWrlSOnKEoAMAzuRw2OnUqVO+G35u2bJF7du3d0pRgJm9957k5yetW5fTNmCAlJoqPfSQ6+oCALNyeILy/fffr2eeeUYxMTFq06aNJOnHH3/U8uXLNX36dH3xxRd2fQFYnTghtWsn5R4ADQuzXrK6zu4mAIBb5PCcHQ+Pgg0GOXuBwcLEnB33Vtzn7GRmSr17S7n+O0A+PtLChdLf/ua6ugCguHPqOju5ZWWvcAbghhYtkoYNk9LTc9r69pWWL3dZSQBw27mpdXaypaamsi0DkI9Tp6S775ZOn85pq1rVuu1DtWquqwsAbkcOT1DOzMzUCy+8oMqVK6tUqVI6fvy4JGnKlCmaP3++0wsEipt+/aTq1XOCjre39ZLVqVMEHQBwBYfDzksvvaRFixZp5syZ8vHxsbU3aNBA8+bNc2pxQHHy3/9abx/PfYnq/vulK1ekRx91WVkAcNtzOOx89NFH+uCDDxQZGSlPT09be+PGjXXw4EGnFgcUB3Fx1ruq+ve37lIuSSEh1s0wP/9cyvU/EwCACzgcds6ePas777wzT3tWVpbSc8/CBG4DAwdag80vv1ife3lJ774r/foru34DgLtwOOzUq1cv30UFP/30UzVt2tQpRQHubtUq68KAH3+c09a9u3VhwCefdF1dAIC8HL4ba+rUqRo8eLDOnj2rrKwsrVy5UocOHdJHH32k1atXF0aNgNu4eFFq3Vo6ejSnLShI2rRJql3bdXUBAK7N4ZGdBx54QF9++aW+/fZb+fv7a+rUqYqNjdWXX36prl27FkaNgFsYOlQqXz4n6Hh6Sm+8YZ2zQ9ABAPd1U+vstG/fXt98842zawHc0urV1tvJr1zJabvnHmn9eiYfA0BxcEuLCgJmlpgotWkj5b7JsEIFKSpKatTIdXUBABzj8GUs4HYwcqRUtmxO0PHwkF55RbpwgaADAMUNIztALlFR0gMPSCkpOW3t2knffWfdvBMAUPwQdgBJyclS27bSTz/ltJUtK33zjdS8uevqAgDcOocuY6Wnp6tmzZqKjY0trHqAIjdunBQQkBN0PDyk556z3mZO0AGA4s+hkR1vb2+lpqYWVi1Akdq0SfrLX6RLl3LaWrWSNmyQSpRwWVkAACdzeILyiBEj9OqrryojI6Mw6gEK3ZUr1hGbjh1zgk5AgBQdLW3bRtABALNxeM7Ojh07FBUVpfXr16thw4by9/e3e33lypVOKw5wtsmTpRkzJMOwPrdYpGeesbYBAMzJ4bBTpkwZ9enTpzBqAQrN9u3Svfda187J1rSptHUrIzkAYHYOh52FCxcWRh1Aobh61Xq56scfc9pKl5a++ELq1MllZQEAitBNLSqYkZGhb7/9Vu+//74u/W/Sw6+//qrk5GSnFgfcihdesI7aZAcdi0UaPVpKSiLoAMDtxOGRnZMnT6p79+46deqU0tLS1LVrV5UuXVqvvvqq0tLSNGfOnMKoEyiwPXukLl2st45na9DAOgG5VCmXlQUAcBGHR3ZGjx6tFi1a6I8//lCJXJMdHnroIUVFRTm1OMARV69KHTpY5+JkB52SJaW1a61r6BB0AOD25PDIzubNm/XDDz/I509r59eoUUNnz551WmGAI2bOlJ59VsrMzGl78knp3XddVxMAwD04HHaysrKUmfsb5X/OnDmj0qVLO6UooKD275c6d5Z++y2nrU4d611W5cq5ri4AgPtw+DLWvffeq9mzZ9ueWywWJScna9q0aerRo4czawOuKTNTioiQGjbMCTp+ftLnn0uxsQQdAEAOh8POa6+9pq1bt6pevXpKTU3V3/72N9slrFdffbUwagTsvPWW5Otr3aE822OPWVdGvv9+19UFAHBPDl/GqlKlivbu3atly5Zp3759Sk5O1pAhQxQZGWk3YRkoDB07Sr//nvP8zjulH36QKlZ0XU0AAPfmcNiRJC8vLw0YMMDZtQD5yr18U3bQ8fWV/vMf6a9/dU1NAIDi46bCzqFDh/TWW28pNjZWklS3bl2NHDlSderUcWpxuL1lZFhvJY+Otm9/5BFpyRLX1AQAKH4cnrOzYsUKNWjQQDExMWrcuLEaN26sXbt2qWHDhlqxYkVh1IjbUK9ekrd33qCzejVBBwDgGIthZO//XDA1a9ZUZGSknn/+ebv2adOm6eOPP9axY8ecWmBRSEpKUmBgoBITExUQEODqcm5rjz4qffRRzq7kkuTvL6WkWH/ev1+qX98lpQEA3ExBv78dHtk5d+6cBg0alKd9wIABOnfunKOHAyRJzzwjeXpKH36YE3T8/KTly6Vt21xbGwCgeHM47HTq1EmbN2/O075lyxa1b9/eKUXh9jF7tuTlZV0BOSvL2ublJb39tvVW8r59XVoeAMAEHJ6gfP/99+uZZ55RTEyM2rRpI0n68ccftXz5ck2fPl1ffPGFXV8gP0uWSI8/LqWl5bR5eEiTJ0t/ukIKAMAtcXjOjodHwQaDLBZLvttKuCPm7BSdb76RHnooZw6OJFks0hNPSB98kP97Dhyw7louMWcHAJCjoN/fN7U3FuCoXbukLl2khAT79oceklaudElJAIDbxE2tswMU1C+/SOHhUlycfXuHDtbtHrz4CwQAFDK+alAoEhKk5s2l48ft2xs1st5d5efnkrIAALchh+/GAq4nNVVq0kQqW9Y+6Nxxh3ThgrR3L0EHAFC0CDtwiowMqVMnqUQJa6DJFhwsnTghHTsmVajgsvIAALcxwg5u2V//at3aYePGnLYyZaSdO6Vz56QaNVxVGQAABZyzk5SUVOADcuv27WP4cGnOnLxbO6xaJXXt6rq6AADIrUBhp0yZMrJYLAU6YHFZWwc3b/p06YUXpNz/r/bxkebOlfLZSQQAAJcqUNj5/vvvbT//8ssvmjhxoh599FGFh4dLkqKjo/Xhhx9qxowZhVMl3MKcOdI//iGlp+e0eXpKM2ZI48e7ri4AAK6nQGGnY8eOtp+ff/55vf7663rkkUdsbffff78aNmyoDz74QIMHD3Z+lXCplSulyEjrnVbZPDykMWOkf/3LdXUBAFAQDk9Qjo6OVosWLfK0t2jRQtu3b3dKUXAPW7ZIAQFSnz45QcdikQYOtF7CIugAAIoDh8NO1apVNXfu3Dzt8+bNU9WqVZ1SFFzrwAHrbeLt20uXLuW09+hh3Zn8o49cVxsAAI5yeAXlN954Q3369NHXX3+t1q1bS5K2b9+uI0eOaMWKFU4vEEUnLk5q2VI6c8a+vU0bafNmtnYAABRPDo/s9OjRQ0eOHNH999+vixcv6uLFi+rVq5cOHz6sHj16FEaNKGTJydJdd0khIfZBp25d68hOdDRBBwBQfDn0FZaenq7u3btrzpw5eumllwqrJhSRjAypbVtpxw779mrVrPtXBQe7pi4AAJzJoZEdb29v7du3r7BqQRHJyJC6d7euepw76FSoIB08KJ08SdABAJiHw5exBgwYoPnz5xdGLSgCAwZYFwBcty6nLSDAOifnwgXr5SwAAMzE4ZkYGRkZWrBggb799ls1b95c/v7+dq+//vrrTisOzjN2rPTGG/ZbO5QoIS1dKj3wgOvqAgCgsDkcdvbv369mzZpJkg4fPmz3WkG3lEDR+de/pEmT7Ld28PaW3n5bGjbMdXUBAFBUHA47ubeOKGqvvPKKJk2apNGjR2v27NmSpNTUVI0dO1bLli1TWlqaunXrpnfffVdBQUEuq9MdfPSRNHSodPVqTpunpzRtmjRliuvqAgCgqDk8Z8dVduzYoffff1+NGjWya3/66af15Zdfavny5dq4caN+/fVX9e7d20VVut7atdadxwcPzgk6Fos0cqR1YjJBBwBwu7mp1VN27typTz75RKdOndLV3EMHklauXOmUwnJLTk5WZGSk5s6dqxdffNHWnpiYqPnz52vJkiW65557JEkLFy5U3bp19eOPP6pNmzZOr8Vd7dghde0qJSbat/frJ/33v66pCQAAd+DwyM6yZcvUtm1bxcbGatWqVUpPT9eBAwf03XffKTAwsDBq1IgRI9SzZ09FRETYtcfExCg9Pd2uvU6dOqpWrZqio6Oveby0tDQlJSXZPYqro0ett4m3amUfdLp0se5OTtABANzuHA47L7/8st544w19+eWX8vHx0b///W8dPHhQ/fr1U7Vq1Zxe4LJly7Rr1y7NmDEjz2txcXHy8fFRmTJl7NqDgoIUFxd3zWPOmDFDgYGBtkdx3NPrt9+ksDCpVi0pPj6nvVkz6coV6dtvWfUYAADpJsLOsWPH1LNnT0mSj4+PUlJSZLFY9PTTT+uDDz5wanGnT5/W6NGjtXjxYvn5+TntuJMmTVJiYqLtcfr0aacdu7ClpkoNG0oVK0q//JLTfued0h9/SDExkhNPFQAAxZ7DYads2bK69L+tsCtXrqz9+/dLkhISEnT58mWnFhcTE6Pz58+rWbNm8vLykpeXlzZu3Kg333xTXl5eCgoK0tWrV5WQkGD3vvj4eAVfZwlgX19fBQQE2D3cXUaGdRfyEiWk/51ySVJoqHT6tHTkiPSnAS4AAKCbCDsdOnTQN998I0n661//qtGjR2vo0KF65JFH1KVLF6cW16VLF/3000/as2eP7dGiRQtFRkbafvb29lZUVJTtPYcOHdKpU6cUHh7u8OfFxDizeud56CHr2jhbtuS0lSsn7d0rnT0rVaniutoAAHB3Ds/qePvtt5WamipJmjx5sry9vfXDDz+oT58++uc//+nU4kqXLq0GDRrYtfn7+6t8+fK29iFDhmjMmDEqV66cAgICNGrUKIWHh5viTqwnnpAWLLBf9djfX/riC+l/N58BAIAbcDjslCtXzvazh4eHJk6c6NSCHPXGG2/Iw8NDffr0sVtUsDibPFl65RUpKyunzddXWrRI6t/fZWW5TP369oEPAABHWAzDsa+RQYMGqXPnzurQoYNq1qxZWHUVqaSkJAUGBuq77xLVubPr5u+8/bb09NPW+TnZvLyk11+XRo1yWVkAALil7O/vxMTE686/dXjOjo+Pj2bMmKFatWqpatWqGjBggObNm6cjR47cUsG3s+XLrXdQjRqVE3Q8PKx7WqWnE3QAALgVDo/sZDt79qw2bdqkjRs3auPGjTp8+LBCQkJ05swZZ9dY6Fw1srNpk9Szp5ScnNNmsUiPPy7Nm1dkZQAAUCwVdGTnppedK1u2rMqXL6+yZcuqTJky8vLyUsWKFW/2cLeVffukzp2lixft2++/X/r8c9fUBACAWTl8GevZZ59V27ZtVb58eU2cOFGpqamaOHGi4uLitHv37sKo0TTOnJEqV5YaN7YPOnffbb1cRdABAMD5HB7ZeeWVV1SxYkVNmzZNvXv3Vu3atQujLlNJSLDuXfXnaU0NGlg38GTFYwAACo/DYWf37t3auHGjNmzYoNdee00+Pj7q2LGjOnXqpE6dOhF+cklNldq1k3btsm+vUcMacipUcElZAADcVm56gnK2vXv36o033tDixYuVlZWlzMxMZ9VWZJw9QTkjQ+reXcq1sLMkqVIlaetW6z5WAADg1hTaBGXDMLR7925t2LBBGzZs0JYtW5SUlKRGjRqpY8eOt1S0GTzyiLRsmX1bYKD0zTdSy5auqQkAgNvZTa2gnJycrMaNG6tjx44aOnSo2rdvrzK3+S6Uo0dLb71lv9JvyZLSihXWUR4AAOAaDoedjz/+WO3bty8WO4UXhZdekqZNk3JfvfPxkd5/X3r0UZeVBQAA/sfhW8979uypgIAAHT16VOvWrdOVK1ckWS9v3U7mz7eGmn/+MyfoeHpKM2dKaWkEHQAA3IXDYef3339Xly5dVLt2bfXo0UPnzp2TZN19fOzYsU4v0N18/rn18tQTT1jXxpGsqx5n72k1frxr6wMAAPYcDjtPP/20vL29derUKZUsWdLW/vDDD2vt2rVOLc6dREdbJxo/+KD0v8EsSdLf/mbdnfz1111WGgAAuA6H5+ysX79e69atU5UqVezaa9WqpZMnTzqtMHdx6JDUvr104YJ9e7du0urV1l3JAQCA+3L4qzolJcVuRCfbxYsX5evr65Si3EFcnNS6tXTqlH17y5bSDz8QcgAAKC4cvozVvn17ffTRR7bnFotFWVlZmjlzpjp37uzU4lwhOVmqX18KCbEPOrVrS5cuSdu3E3QAAChOHP7anjlzprp06aKdO3fq6tWrmjBhgg4cOKCLFy9q69athVFjkRkxQoqNtW+rUsU6X+dPV+0AAEAx4fDIToMGDXT48GHdfffdeuCBB5SSkqLevXtr9+7dqlmzZmHUWGRyB53y5aX9+6XTpwk6AAAUZw6N7KSnp6t79+6aM2eOJk+eXFg1uVTp0tKaNdLdd7u6EgAA4AwOjex4e3tr3759hVWLy02fLiUlEXQAADAThy9jDRgwQPPnzy+MWlyufXtXVwAAAJzN4QnKGRkZWrBggb799ls1b95c/v7+dq+/zup6AADAjTgcdvbv369mzZpJkg4fPmz3msVicU5VAAAATuJw2Pn+++8Low4AAIBC4fCcHQAAgOKEsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsJNL8+aurgAAADgbYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJgaYQcAAJiaW4edGTNmqGXLlipdurQqVaqkBx98UIcOHbLrk5qaqhEjRqh8+fIqVaqU+vTpo/j4eBdVDAAA3I1bh52NGzdqxIgR+vHHH/XNN98oPT1d9957r1JSUmx9nn76aX355Zdavny5Nm7cqF9//VW9e/d2YdUAAMCdWAzDMFxdREFduHBBlSpV0saNG9WhQwclJiaqYsWKWrJkifr27StJOnjwoOrWravo6Gi1adOmQMdNSkpSYGCgEhMTFRAQUJi/AgAAcJKCfn+79cjOnyUmJkqSypUrJ0mKiYlRenq6IiIibH3q1KmjatWqKTo6+prHSUtLU1JSkt0DAACYU7EJO1lZWXrqqafUrl07NWjQQJIUFxcnHx8flSlTxq5vUFCQ4uLirnmsGTNmKDAw0PaoWrVqYZYOAABcqNiEnREjRmj//v1atmzZLR9r0qRJSkxMtD1Onz7thAoBAIA78nJ1AQUxcuRIrV69Wps2bVKVKlVs7cHBwbp69aoSEhLsRnfi4+MVHBx8zeP5+vrK19e3MEsGAABuwq1HdgzD0MiRI7Vq1Sp99913CgsLs3u9efPm8vb2VlRUlK3t0KFDOnXqlMLDw4u6XAAA4IbcemRnxIgRWrJkiT7//HOVLl3aNg8nMDBQJUqUUGBgoIYMGaIxY8aoXLlyCggI0KhRoxQeHl7gO7EAAIC5ufWt5xaLJd/2hQsX6tFHH5VkXVRw7NixWrp0qdLS0tStWze9++67172M9Wfceg4AQPFT0O9vtw47RYWwAwBA8WPKdXYAAAAcRdgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmZpqw884776hGjRry8/NT69attX37dleXBAAA3IApws5///tfjRkzRtOmTdOuXbvUuHFjdevWTefPn3d1aQAAwMVMEXZef/11DR06VI899pjq1aunOXPmqGTJklqwYIGrSwMAAC5W7MPO1atXFRMTo4iICFubh4eHIiIiFB0d7cLKAACAO/BydQG36rffflNmZqaCgoLs2oOCgnTw4MF835OWlqa0tDTb88TERElSUlJS4RUKAACcKvt72zCM6/Yr9mHnZsyYMUPTp0/P0161alUXVAMAAG7FpUuXFBgYeM3Xi33YqVChgjw9PRUfH2/XHh8fr+Dg4HzfM2nSJI0ZM8b2PCEhQdWrV9epU6eue7KQV1JSkqpWrarTp08rICDA1eUUK5y7W8P5u3mcu5vHubs1zj5/hmHo0qVLCg0NvW6/Yh92fHx81Lx5c0VFRenBBx+UJGVlZSkqKkojR47M9z2+vr7y9fXN0x4YGMgf700KCAjg3N0kzt2t4fzdPM7dzePc3Rpnnr+CDFIU+7AjSWPGjNHgwYPVokULtWrVSrNnz1ZKSooee+wxV5cGAABczBRh5+GHH9aFCxc0depUxcXFqUmTJlq7dm2eScsAAOD2Y4qwI0kjR4685mWrG/H19dW0adPyvbSF6+Pc3TzO3a3h/N08zt3N49zdGledP4txo/u1AAAAirFiv6ggAADA9RB2AACAqRF2AACAqRF2AACAqd02Yeedd95RjRo15Ofnp9atW2v79u3X7b98+XLVqVNHfn5+atiwodasWVNElbofR87d3Llz1b59e5UtW1Zly5ZVRETEDc+1mTn6d5dt2bJlslgstoUyb1eOnr+EhASNGDFCISEh8vX1Ve3atW/b/+06eu5mz56tu+66SyVKlFDVqlX19NNPKzU1tYiqdR+bNm1Sr169FBoaKovFos8+++yG79mwYYOaNWsmX19f3XnnnVq0aFGh1+mOHD13K1euVNeuXVWxYkUFBAQoPDxc69atK5zijNvAsmXLDB8fH2PBggXGgQMHjKFDhxplypQx4uPj8+2/detWw9PT05g5c6bx888/G//85z8Nb29v46effiriyl3P0XP3t7/9zXjnnXeM3bt3G7Gxscajjz5qBAYGGmfOnCniyl3P0XOX7cSJE0blypWN9u3bGw888EDRFOuGHD1/aWlpRosWLYwePXoYW7ZsMU6cOGFs2LDB2LNnTxFX7nqOnrvFixcbvr6+xuLFi40TJ04Y69atM0JCQoynn366iCt3vTVr1hiTJ082Vq5caUgyVq1add3+x48fN0qWLGmMGTPG+Pnnn4233nrL8PT0NNauXVs0BbsRR8/d6NGjjVdffdXYvn27cfjwYWPSpEmGt7e3sWvXLqfXdluEnVatWhkjRoywPc/MzDRCQ0ONGTNm5Nu/X79+Rs+ePe3aWrdubfz9738v1DrdkaPn7s8yMjKM0qVLGx9++GFhlei2bubcZWRkGG3btjXmzZtnDB48+LYOO46ev/fee8+44447jKtXrxZViW7L0XM3YsQI45577rFrGzNmjNGuXbtCrdPdFeQLe8KECUb9+vXt2h5++GGjW7duhViZ+yvIuctPvXr1jOnTpzu9HtNfxrp69apiYmIUERFha/Pw8FBERISio6PzfU90dLRdf0nq1q3bNfub1c2cuz+7fPmy0tPTVa5cucIq0y3d7Ll7/vnnValSJQ0ZMqQoynRbN3P+vvjiC4WHh2vEiBEKCgpSgwYN9PLL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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "time to jit: 0:00:09.972583\n",
      "time to train: 0:00:44.563139\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAS8tJREFUeJzt3Xd8VFXex/HvpEMgoadQI4L03gLSJAjCYgEWcUNREfaRsihNkAXEhrKorBWl6kpZEbAgAhqlGimhCYaONElAMQkJJKTc54/ZTDImQAYmmcnl83695vVkzpy588t9sszXc889x2IYhiEAAACT8nB1AQAAAIWJsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAMAAEyNsAPArdWoUUMWiyXfR61atWz9Tp8+renTp6tVq1YqW7asKlSooE6dOunbb78t8GedO3dOw4YNU1hYmEqUKKGaNWtqzJgx+v333/P0ffvtt1W3bl35+vqqcuXKGjNmjFJSUuz6HDx4UBMmTFCTJk1UunRphYSEqGfPntq5c+fNnxAADrOwNxYAd/bZZ58pOTnZru3kyZP65z//qeHDh+udd96RZA0fEyZM0IMPPqh27dopIyNDH330kXbt2qUFCxboscceu+7nJCcnq0GDBkpJSdHw4cNVtWpV7d27V++//77q16+vmJgYeXhY//vwmWee0cyZM9W3b1916dJFP//8s9577z3dc889Wrdune2Y48aN0/z589WnTx+1atVKiYmJev/99/XLL79o7dq1ioiIcPLZApAvAwCKmRdeeMGQZGzdutXWtn//fuPChQt2/VJTU406deoYVapUueExFy9ebEgyVq9ebdc+depUQ5Kxa9cuwzAM49dffzW8vLyMgQMH2vV76623DEnGF198YWvbuXOncenSJbt+v/32m1GxYkWjXbt2BftlAdwyLmMBuCXff/+9LBaLVq1alee1JUuWyGKxKDo62qmfuWTJEoWFhalt27a2tvr166tChQp2/Xx9fdWjRw+dOXNGly5duu4xk5KSJElBQUF27SEhIZKkEiVKSJKio6OVkZGh/v372/XLfr5s2TJbW/PmzVWqVCm7fuXLl1f79u0VGxt7w98TgHN4uboAAMVbp06dVLVqVS1evFgPPfSQ3WuLFy9WzZo1FR4errS0tBsGjmx/Di257d69W7GxsZo8eXKBjhUXF6eSJUuqZMmS1+3XoUMHeXh4aPTo0XrttddUpUoV7du3Ty+99JIefPBB1alTR5KUlpYmKSf8ZMs+fkxMTIFqut7vCMC5GNkBcEssFosGDBig1atXKzEx0dZ+4cIFrV+/XgMGDJAkLV26VBUrVizQ43oWL14sSYqMjLxhbUePHtXKlSvVp08feXp6XrdvvXr19MEHH+jnn39WeHi4qlatqp49e6pLly5avny5rd9dd90lSdq6davd+zdv3ixJOnv27HU/Z/PmzYqOjtbDDz98w/oBOAcTlAHcsoMHD6pu3bqaN2+ehgwZIsk6YXjUqFE6cuSI7rzzTp07d04HDhwo0PGuNXE3KytL1apVU6VKlbRr167rHuPy5ctq166dTp48qf379ys0NPSGn7t27Vq98cYb6tGjh6pXr67NmzfrzTff1OjRozVr1ixbvzZt2ujAgQN688031blzZ8XGxurJJ5/Ur7/+qqysLGVkZOR7/PPnz6t58+by8fHR3r1781ziAlBIXD1pCIA5tGzZ0ujcubPteZs2bYw2bdo49TO+++47Q5Ixa9as6/bLyMgwevXqZfj4+BhRUVEFOvaWLVsMT09PY8eOHXbtzz33nGGxWIwDBw7Y2s6cOWO0a9fOkGRIMjw9PY3x48cbrVq1MgIDA/M9fnJystGyZUsjMDDQ+OmnnwpUEwDnYM4OAKcYNGiQRo8erTNnzigtLU0//vij3n77bdvrV65csbvMdT3BwcH5ti9evFgeHh565JFHrvv+oUOHavXq1Vq8eLHuueeeAn3m+++/r6CgILVo0cKu/f7779dzzz2nH374QfXq1ZMkVa5cWVu2bNGRI0cUFxenWrVqKTg4WKGhoapdu3aeY1+9elW9e/fWvn37tG7dOjVo0KBANQFwDsIOAKfo37+/xowZo6VLl+rKlSvy9va2m5fy3//+94Zr3WQz8rm6npaWphUrVqhTp07XvSQ1fvx4LVy4ULNnz75hKMotPj5emZmZedrT09MlKd9LU7Vq1bItbPjzzz/r3LlzevTRR+36ZGVladCgQYqKitInn3yijh07FrgmAM5B2AHgFBUqVNB9992njz/+WKmpqerevbvdHUfdunXTN998c9PHX7NmjRISEq47Mflf//qXZs2apWeffVajR4++Zr/E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Ng8nMDBQJUqUUGBgoIYMGaIxY8aoXLlyCggI0KhRoxQeHl7gO7EAAIC5ufWt5xaLJd/2hQsX6tFHH5VkXVRw7NixWrp0qdLS0tStWze9++67172M9Wfceg4AQPFT0O9vtw47RYWwAwBA8WPKdXYAAAAcRdgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmRtgBAACmZpqw884776hGjRry8/NT69attX37dleXBAAA3IApws5///tfjRkzRtOmTdOuXbvUuHFjdevWTefPn3d1aQAAwMVMEXZef/11DR06VI899pjq1aunOXPmqGTJklqwYIGrSwMAAC5W7MPO1atXFRMTo4iICFubh4eHIiIiFB0d7cLKAACAO/BydQG36rffflNmZqaCgoLs2oOCgnTw4MF835OWlqa0tDTb88TERElSUlJS4RUKAACcKvt72zCM6/Yr9mHnZsyYMUPTp0/P0161alUXVAMAAG7FpUuXFBgYeM3Xi33YqVChgjw9PRUfH2/XHh8fr+Dg4HzfM2nSJI0ZM8b2PCEhQdWrV9epU6eue7KQV1JSkqpWrarTp08rICDA1eUUK5y7W8P5u3mcu5vHubs1zj5/hmHo0qVLCg0NvW6/Yh92fHx81Lx5c0VFRenBBx+UJGVlZSkqKkojR47M9z2+vr7y9fXN0x4YGMgf700KCAjg3N0kzt2t4fzdPM7dzePc3Rpnnr+CDFIU+7AjSWPGjNHgwYPVokULtWrVSrNnz1ZKSooee+wxV5cGAABczBRh5+GHH9aFCxc0depUxcXFqUmTJlq7dm2eScsAAOD2Y4qwI0kjR4685mWrG/H19dW0adPyvbSF6+Pc3TzO3a3h/N08zt3N49zdGledP4txo/u1AAAAirFiv6ggAADA9RB2AACAqRF2AACAqRF2AACAqd02Yeedd95RjRo15Ofnp9atW2v79u3X7b98+XLVqVNHfn5+atiwodasWVNElbofR87d3Llz1b59e5UtW1Zly5ZVRETEDc+1mTn6d5dt2bJlslgstoUyb1eOnr+EhASNGDFCISEh8vX1Ve3atW/b/+06eu5mz56tu+66SyVKlFDVqlX19NNPKzU1tYiqdR+bNm1Sr169FBoaKovFos8+++yG79mwYYOaNWsmX19f3XnnnVq0aFGh1+mOHD13K1euVNeuXVWxYkUFBAQoPDxc69atK5zijNvAsmXLDB8fH2PBggXGgQMHjKFDhxplypQx4uPj8+2/detWw9PT05g5c6bx888/G//85z8Nb29v46effiriyl3P0XP3t7/9zXjnnXeM3bt3G7Gxscajjz5qBAYGGmfOnCniyl3P0XOX7cSJE0blypWN9u3bGw888EDRFOuGHD1/aWlpRosWLYwePXoYW7ZsMU6cOGFs2LDB2LNnTxFX7nqOnrvFixcbvr6+xuLFi40TJ04Y69atM0JCQoynn366iCt3vTVr1hiTJ082Vq5caUgyVq1add3+x48fN0qWLGmMGTPG+Pnnn4233nrL8PT0NNauXVs0BbsRR8/d6NGjjVdffdXYvn27cfjwYWPSpEmGt7e3sWvXLqfXdluEnVatWhkjRoywPc/MzDRCQ0ONGTNm5Nu/X79+Rs+ePe3aWrdubfz9738v1DrdkaPn7s8yMjKM0qVLGx9++GFhlei2bubcZWRkGG3btjXmzZtnDB48+LYOO46ev/fee8+44447jKtXrxZViW7L0XM3YsQI45577rFrGzNmjNGuXbtCrdPdFeQLe8KECUb9+vXt2h5++GGjW7duhViZ+yvIuctPvXr1jOnTpzu9HtNfxrp69apiYmIUERFha/Pw8FBERISio6PzfU90dLRdf0nq1q3bNfub1c2cuz+7fPmy0tPTVa5cucIq0y3d7Ll7/vnnValSJQ0ZMqQoynRbN3P+vvjiC4WHh2vEiBEKCgpSgwYN9PLL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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "make_inference_fn, params, metrics = train_fn(environment=env)\n",
    "print(f\"time to jit: {times[1] - times[0]}\")\n",
    "print(f\"time to train: {times[-1] - times[1]}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "076c1ca1",
   "metadata": {},
   "source": [
    "#### Visualize the Policy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "0cd8dec1",
   "metadata": {
    "lines_to_next_cell": 2
   },
   "outputs": [],
   "source": [
    "jit_reset = jax.jit(env.reset)\n",
    "jit_step = jax.jit(env.step)\n",
    "jit_inference_fn = jax.jit(make_inference_fn(params, deterministic=True))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64532268",
   "metadata": {},
   "outputs": [],
   "source": [
    "rng = jax.random.PRNGKey(42)\n",
    "rollout = []\n",
    "n_episodes = 1\n",
    "\n",
    "for _ in range(n_episodes):\n",
    "  key_rng = jax.random.split(rng, num_envs)\n",
    "  state = jit_reset(key_rng)\n",
    "  rollout.append(unvmap(state))\n",
    "  for i in range(episode_length):\n",
    "    act_rng, rng = jax.random.split(rng)\n",
    "    act_rng = jax.random.split(act_rng, num_envs)\n",
    "    ctrl, _ = jit_inference_fn(state.obs, act_rng)\n",
    "    state = jit_step(state, ctrl)\n",
    "    rollout.append(unvmap(state))\n",
    "\n",
    "render_every = 1\n",
    "frames = env.render(rollout[::render_every], camera=\"fixed\")\n",
    "rewards = [s.reward for s in rollout]\n",
    "media.show_video(frames, fps=1.0 / env.dt / render_every)\n",
    "\n",
    "plt.plot(np.convolve(rewards, np.ones(10) / 10, mode=\"valid\"))\n",
    "plt.xlabel(\"time step\")\n",
    "plt.ylabel(\"reward\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eddb3fc3",
   "metadata": {},
   "source": [
    "🙌 See you in Part 2 of pixels-based training with Madrona-MJX, where we'll cover how to use visual domain randomization to transfer policies to the real world!"
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "encoding": "# coding: utf-8",
   "executable": "/usr/bin/env python",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": "vision_benchmark",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
